package utils.parser
{
	import flash.geom.Vector3D;
	
	import utils.base.BaseFrame;
	import utils.base.Hierarchy;
	import utils.base.Joint;
	import utils.base.MeshVertex;
	import utils.base.Weight;
	import utils.math.Quaternion;

	public class Stage3D_md5anim_parser
	{
		private const LINE_FEED:String = String.fromCharCode(10);
		private const SPACE:String = String.fromCharCode(32);
		private const HIERARCHY:String = "hierarchy";
		private const BOUNDS:String = "bounds";
		private const BASEFRAME:String = "baseframe";
		private const FRAME:String = "frame";
		
		private var _hierarchyVector:Vector.<Hierarchy>;
		private var _baseFrameVector:Vector.<BaseFrame>;
		private var _frameVector:Vector.<Vector.<Number>>;
		private var _tempFrameVector:Vector.<Number>;
		private var _allFrameVector:Vector.<Vector.<BaseFrame>>;
		private var _jointAnimVecter:Vector.<Vector.<Joint>>;
		
		private var _jointKeyAnimVecter:Vector.<Vector.<Joint>>;
		
		private var _jointsAry:Vector.<Joint>;
		private var _meshVeterAry:Vector.<MeshVertex>;
		private var _weightAry:Vector.<Weight>;
		
		private var flag:String; 
		private var frameNum:int;
		public function Stage3D_md5anim_parser(definition:String)
		{
			_hierarchyVector = new Vector.<Hierarchy>;
			_baseFrameVector = new Vector.<BaseFrame>;
			_frameVector = new Vector.<Vector.<Number>>;
			_allFrameVector = new Vector.<Vector.<BaseFrame>>;
			_jointAnimVecter = new Vector.<Vector.<Joint>>;
			
			_jointKeyAnimVecter = new Vector.<Vector.<Joint>>;
			
			var lines:Array = definition.split(LINE_FEED);
			var loop:uint = lines.length;
			
			for(var i:uint = 0; i < loop; ++i){
				var t:String = lines[i];
				if(t.search(HIERARCHY + " {") == 0){
					flag = HIERARCHY;
				}else if(t.search(BOUNDS + " {") == 0){
					flag = BOUNDS;
				}else if(t.search(BASEFRAME + " {") == 0){
					flag = BASEFRAME;
				}else if(t.search(FRAME) == 0){
					flag = FRAME;
				}
				parseLine(t);
			}
			trace("com");
		}
		public function setBaseInfo(mesh:Stage3D_md5mesh_parser):void{
			this._jointsAry = mesh.jointsAry;
			this._meshVeterAry = mesh.meshVeterAry;
			this._weightAry = mesh.weightAry;
			processData();
			//processKeyFrame();
		}
		
		private function parseLine(line:String):void{
			if(flag == HIERARCHY){
				processHierarchy(line);
			}else if(flag == BOUNDS){
				//processMesh(line);
			}else if(flag == BASEFRAME){
				processBaseFrame(line);
			}else if(flag == FRAME){
				processFrame(line);
			}
		}
		
		private function processHierarchy(line:String):void{
			var ary:Array = line.split("\t");
			var str:String;
			if(ary.length>=3){
				str = ary[2];
				ary = str.split(SPACE);
				_hierarchyVector.push(new Hierarchy(ary[0],ary[1],ary[2]));
			}
		}
		private function processBaseFrame(line:String):void{
			var r:RegExp = /"\t(.*?) .?/gi;
			var re:* = r.exec(line);
			var index:int;
			if(re){
				index = int(re[1]);
			}
			r = /\( (.*?) \).?/gi;
			re = r.exec(line);
			var ar:Array = new Array;
			while(re)
			{
				ar.push(re[1]);
				re = r.exec(line);
			}
			if(ar.length != 2){
				return;
			}
			var baseframe:BaseFrame = new BaseFrame(getVecter3DByString(ar[1]),getVecter3DByString(ar[0]));
			_baseFrameVector.push(baseframe);
		}
		
		private function processFrame(line:String):void{
			var ary:Array;
			if(line.search(FRAME) == 0 && line.search("{") != -1){
				ary = line.split(SPACE);
				frameNum = int(ary[1]);
				_tempFrameVector = new Vector.<Number>;
				_frameVector.push(_tempFrameVector);
			}
			if(line.search("\t") != -1 && _tempFrameVector){
				trace(line)
				line = line.slice(0,line.length-2);
				line = line.slice(1,line.length);
				line = "\t " + line;
				trace(line)
				ary = line.split(SPACE);
				for(var i:int=1;i<ary.length;i++){
					_tempFrameVector.push(Number(ary[i]));
				}
			}
		}
		private function processData():void{
			for(var i:int=0;i<_frameVector.length;i++){
				trace("**********************")
				var frameData:Vector.<Number> = _frameVector[i];
				var jointAry:Vector.<Joint> = new Vector.<Joint>;
				_jointAnimVecter.push(jointAry);
				for(var j:int=0;j<_baseFrameVector.length;j++){
					var baseFrame:BaseFrame = _baseFrameVector[j];
					var hierarchy:Hierarchy = _hierarchyVector[j];
					var k:int = 0;
					var pos:Vector3D = baseFrame.pos.clone();// new Vector3D(baseFrame.pos.x,baseFrame.pos.y,baseFrame.pos.z);
					var orient:Quaternion = new Quaternion(baseFrame.orient.x,baseFrame.orient.y,baseFrame.orient.z);
					if (hierarchy.flag & 1){
						pos.x = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 2){
						pos.y = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 4){
						pos.z = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 8){
						orient.x = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 16){
						orient.y = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 32){
						orient.z = frameData[hierarchy.startIndex + k];
						++k;
					}
					orient.computeW();
					//if(i<60 && i>=40){
						trace(i,pos.x,pos.y,pos.z,orient.x,orient.y,orient.z)
					//}
					var joint:Joint = _jointsAry[j];
					var newJoint:Joint;// = new Joint();
					if(hierarchy.parentIndex < 0){
						newJoint = new Joint(hierarchy.parentIndex,pos,orient);
					}else{
						//var quaternion:Quaternion = new Quaternion();
						var parentJoint:Joint = jointAry[joint.parentIndex];
						var rpos:Vector3D = orient.quaternionRotate(parentJoint.orient,pos);
						pos = rpos.add(parentJoint.pos);
						orient.multiply(parentJoint.orient,orient);
						orient.normalize(1);
						newJoint = new Joint(hierarchy.parentIndex,pos,orient);
					}
					jointAry.push(newJoint);
				}
			}
		}
		
		private function processKeyFrame():void{
			for(var i:int=0;i<_frameVector.length;i++){
				var frameData:Vector.<Number> = _frameVector[i];
				var jointAry:Vector.<Joint> = new Vector.<Joint>;
				_jointKeyAnimVecter.push(jointAry);
				for(var j:int=0;j<_baseFrameVector.length;j++){
					var baseFrame:BaseFrame = _baseFrameVector[j];
					var hierarchy:Hierarchy = _hierarchyVector[j];
					var k:int = 0;
					var pos:Vector3D = baseFrame.pos.clone();// new Vector3D(baseFrame.pos.x,baseFrame.pos.y,baseFrame.pos.z);
					var orient:Quaternion = new Quaternion(baseFrame.orient.x,baseFrame.orient.y,baseFrame.orient.z);
					if (hierarchy.flag & 1){
						pos.x = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 2){
						pos.y = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 4){
						pos.z = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 8){
						orient.x = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 16){
						orient.y = frameData[hierarchy.startIndex + k];
						++k;
					}
					if (hierarchy.flag & 32){
						orient.z = frameData[hierarchy.startIndex + k];
						++k;
					}
					orient.computeW();
					
					var joint:Joint = _jointsAry[j];
					var newJoint:Joint = new Joint(hierarchy.parentIndex,pos,orient);// = new Joint();
					jointAry.push(newJoint);
				}
			}
			getFrame();
		}
		
		private function getFrame():void{
			var jointframeVecter:Vector.<Vector.<Joint>> = new Vector.<Vector.<Joint>>;
			for(var i:int=0;i<_jointKeyAnimVecter.length-1;i++){
				var preFrame:Vector.<Joint> = _jointKeyAnimVecter[i];
				var nextFrame:Vector.<Joint> = _jointKeyAnimVecter[i+1];
				jointframeVecter.push(preFrame);
				var t:Number = 0.2;
				while(t < 1){
					var jointAry:Vector.<Joint> = new Vector.<Joint>;
					for(var j:int=0;j<preFrame.length;j++){
						jointAry.push(interJont(preFrame[j],nextFrame[j],t));
					}
					jointframeVecter.push(jointAry);
					t += 0.2;
				}
				
			}
			processResultFrame(jointframeVecter);
		}
		private function processResultFrame(jointframeVecter:Vector.<Vector.<Joint>>):void{
			for(var i:int=0;i<jointframeVecter.length;i++){
				var jointArys:Vector.<Joint> = jointframeVecter[i];
				var newJointAry:Vector.<Joint> = new Vector.<Joint>;
				_jointAnimVecter.push(newJointAry);
				for(var j:int=0;j<jointArys.length;j++){
					var traget:Joint = jointArys[j];
					var pos:Vector3D = traget.pos;
					var orient:Quaternion = traget.orient;
					
					var joint:Joint = _jointsAry[j];
					var newJoint:Joint;// = new Joint();
					if(traget.parentIndex < 0){
						newJoint = new Joint(traget.parentIndex,pos,orient);
					}else{
						//var quaternion:Quaternion = new Quaternion();
						var parentJoint:Joint = newJointAry[joint.parentIndex];
						var rpos:Vector3D = orient.quaternionRotate(parentJoint.orient,pos);
						pos = rpos.add(parentJoint.pos);
						orient.multiply(parentJoint.orient,orient);
						orient.normalize(1);
						newJoint = new Joint(traget.parentIndex,pos,orient);
					}
					newJointAry.push(newJoint);
					
				}
			}
		}
		private function interJont(firstJoint:Joint,secondJoint:Joint,t:Number):Joint{
			//trace("t:" + t)
			var firstPos:Vector3D = firstJoint.pos.clone();
			var secondPos:Vector3D = secondJoint.pos.clone();
			
			firstPos.scaleBy(1-t);
			secondPos.scaleBy(t);
			var newPos:Vector3D = firstPos.add(secondPos);
			
			/*trace(firstJoint.orient.x,firstJoint.orient.y,firstJoint.orient.z);
			trace(secondJoint.orient.x,secondJoint.orient.y,secondJoint.orient.z);
			trace(firstJoint.orient.x/secondJoint.orient.x,
				firstJoint.orient.y/secondJoint.orient.y,firstJoint.orient.z/secondJoint.orient.z)*/
			
			var orient:Quaternion = new Quaternion();
			orient.slerp(firstJoint.orient,secondJoint.orient,t);
			
			return new Joint(firstJoint.parentIndex,newPos,orient)
			
		}
		
		private function getVecter3DByString(str:String):Vector3D{
			var ary:Array = str.split(SPACE);
			return new Vector3D(ary[0],ary[1],ary[2]);
		}

		public function get jointAnimVecter():Vector.<Vector.<Joint>>
		{
			return _jointAnimVecter;
		}

		
	}
}
